﻿using CommData;
using CommHelper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace FrmSocketTest
{
    public class SocketClient
    {
        private static SocketClient _socketClient = null;

        public static SocketClient GetSocketClient
        {
            get
            {
                if (_socketClient == null)
                {
                    _socketClient = new SocketClient();
                }
                return SocketClient._socketClient;
            }
        }

        /// <summary>
        /// socket接受事件参数
        /// </summary>
        protected SocketAsyncEventArgs _receiveEventArgs;

        private ClientReceiveManage _clientreceive = new ClientReceiveManage();

        protected SocketAsyncEventArgs _connectArgs;

        private Socket _connectSocket;

        public bool Connected
        {
            get { return _connectSocket != null && _connectSocket.Connected; }
        }

        private List<byte> _listReceiveByte = new List<byte>();

        private int _asyncReceiveBufferSize = 1024000;

        public int AsyncReceiveBufferSize
        {
            get { return _asyncReceiveBufferSize; }
            set { _asyncReceiveBufferSize = value; }
        }

        private int _requestlength = -1;
        private byte[] _rquestBodyBytes = null;
        private string _methodName = string.Empty;
        private int _errCode = 0;
        private uint _iptoint = 0;

        /// <summary>
        /// 返回数据是否为当前机器操作
        /// </summary>
        public bool IsLocal
        {
            get { return _iptoint == CommHelper.NetHelper.Iptoint; }
        }

        public SocketClient()
        {
            _receiveEventArgs = new SocketAsyncEventArgs();
            var asyncReceiveBuffer = new byte[_asyncReceiveBufferSize];
            _receiveEventArgs.SetBuffer(asyncReceiveBuffer, 0, asyncReceiveBuffer.Length);
            _receiveEventArgs.SetBuffer(0, _asyncReceiveBufferSize);
            _receiveEventArgs.Completed += connectArgs_Completed;
        }

        private void connectArgs_Completed(object sender, SocketAsyncEventArgs asyncEventArgs)
        {
            try
            {
                if (asyncEventArgs.SocketError != SocketError.Success)
                {
                    CloseClientSocket();
                    return;
                }
                if (asyncEventArgs.LastOperation == SocketAsyncOperation.Receive)
                {
                    ProcessReceive(asyncEventArgs);
                }
                else if (asyncEventArgs.LastOperation == SocketAsyncOperation.Send) { }
                else if (asyncEventArgs.LastOperation == SocketAsyncOperation.Connect)
                {
                    Receive();
                }
            }
            catch (Exception E)
            {
                LogHelper.WriteErrorLog(E.Message);
            }
        }

        public void Receive()
        {
            if (_connectSocket == null)
            {
                return;
            }
            bool willRaiseEvent = _connectSocket.ReceiveAsync(_receiveEventArgs); //投递接收请求
            if (!willRaiseEvent)
            {
                ProcessReceive(_receiveEventArgs);
            }
        }

        private void ProcessReceive(SocketAsyncEventArgs receiveEventArgs)
        {
            if (_connectSocket == null)
                return;
            if (receiveEventArgs.BytesTransferred > 0 && receiveEventArgs.SocketError == SocketError.Success)
            {
                lock (_listReceiveByte)
                {
                    var tmpbytes = new byte[receiveEventArgs.BytesTransferred];
                    receiveEventArgs.Buffer.ToList().CopyTo(receiveEventArgs.Offset, tmpbytes, 0, receiveEventArgs.BytesTransferred);
                    _listReceiveByte.AddRange(tmpbytes);
                    if (_listReceiveByte.Count > 0)
                    {
                        OparReceive();
                    }
                }
                Receive();
            }
            else
            {
                CloseClientSocket();
            }
        }

        /// <summary>
        /// 接收数据处理
        /// </summary>
        private void OparReceive()
        {
            try
            {
                MessageStatus messagestatus = CommHelper.NetworkDataHelper.GetNetworkDataHelper.CheckData(_listReceiveByte.ToArray(),
                    ref _requestlength, ref _rquestBodyBytes, ref _methodName, ref _errCode, ref _iptoint);
                switch (messagestatus)
                {
                    case MessageStatus.Packet_Length_Error:
                        break;

                    case MessageStatus.Analysis_Error:
                        CloseClientSocket();
                        break;

                    case MessageStatus.Success:
                        _listReceiveByte.RemoveRange(0, _requestlength + NetworkDataHelper.GetNetworkDataHelper.DataHeaderLength);
                        _requestlength = -1;
                        DealData(_methodName, _rquestBodyBytes, _errCode);
                        if (_listReceiveByte.Count > 0)
                        {
                            OparReceive();
                        }
                        break;
                }
            }
            catch (Exception ex)
            {
                CommHelper.ConsoleHelper.WriteLine(ex.Message);
            }
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="listsendarray"></param>
        public List<byte> SendData(byte[] listsendarray)
        {
            if (_connectSocket != null && listsendarray == null)
                return null;
            try
            {
                _receiveEventArgs.Completed -= connectArgs_Completed;
                int sendDataLenther = 0;
                int bytelength = listsendarray.Length;
                while (sendDataLenther < bytelength)
                {
                    sendDataLenther += _connectSocket.Send(listsendarray, sendDataLenther, bytelength - sendDataLenther, SocketFlags.None);
                }
                byte[] bytes = new byte[_asyncReceiveBufferSize];
                var listbyte = new List<byte>();
                byte[] tmpbytes = null;
                int length = 1;
                while (length > 0)
                {
                    length = _connectSocket.Receive(bytes, bytes.Length, SocketFlags.None);
                    tmpbytes = new byte[length];
                    bytes.ToList().CopyTo(0, tmpbytes, 0, length);
                    listbyte.AddRange(tmpbytes);
                }
                return listbyte;
            }
            catch (Exception E)
            {
                CloseClientSocket();
                LogHelper.WriteErrorLog(E.Message);
            }
            finally
            {
                _receiveEventArgs.Completed += connectArgs_Completed;
            }
            return null;
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="listsendarray"></param>
        public void SendAsyncData(byte[] listsendarray)
        {
            if (_connectSocket == null || listsendarray == null)
                return;
            try
            {
                int sendDataLenther = 0;
                int bytelength = listsendarray.Length;
                while (sendDataLenther < bytelength)
                {
                    sendDataLenther += _connectSocket.Send(listsendarray, sendDataLenther, bytelength - sendDataLenther, SocketFlags.None);
                }
            }
            catch (Exception E)
            {
                CloseClientSocket();
                // LogHelper.WriteErrorLog(E.Message);
                throw E;
            }
        }

        /// <summary>
        /// 处理数据
        /// </summary>
        /// <param name="methodName"></param>
        /// <param name="requestBody"></param>
        private void DealData(string methodName, byte[] requestBody, int errcode)
        {
            try
            {
                _clientreceive.OparData(methodName, requestBody, errcode);
            }
            catch (Exception e)
            {
                LogHelper.WriteErrorLog(e.Message);
            }
        }

        /// <summary>
        /// 开启连接线程
        /// </summary>
        /// <param name="isasync"></param>
        public void ConnectSocket(bool isasync)
        {
            System.Threading.Thread thResourceLoader = new System.Threading.Thread(new System.Threading.ThreadStart(new Action(() => { Connect(isasync); })));
            thResourceLoader.Name = "Resource Loader";
            thResourceLoader.Priority = System.Threading.ThreadPriority.Highest;
            thResourceLoader.Start();
        }

        /// <summary>
        /// 连接服务端
        /// </summary>
        private void Connect(bool isasync)
        {
            if (CloseClientSocket())
            {
                return;
            }
            _connectArgs = new SocketAsyncEventArgs();
            _connectArgs.RemoteEndPoint = new System.Net.IPEndPoint(
                        System.Net.IPAddress.Parse(
                            CommHelper.AppSettingsHelper.GetText("ServerIp")), CommHelper.AppSettingsHelper.GetInt("ServerPort")
                        );
            _connectArgs.Completed += connectArgs_Completed;
            _requestlength = -1;
            _connectSocket = new Socket(System.Net.IPAddress.Any.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            _connectSocket.SendTimeout = CommHelper.AppSettingsHelper.GetInt("Timeout");
            _connectSocket.ReceiveTimeout = CommHelper.AppSettingsHelper.GetInt("Timeout");
            _connectArgs.AcceptSocket = _connectSocket;
            if (isasync)
            {
                _connectSocket.ConnectAsync(_connectArgs);
            }
            else
            {
                _connectSocket.Connect(_connectArgs.RemoteEndPoint);
            }
        }

        /// <summary>
        /// 关闭socket并清理接口
        /// </summary>
        public bool CloseClientSocket()
        {
            if (_connectSocket == null)
                return false;
            try
            {
                if (_connectSocket.Connected)
                {
                    _connectArgs.Completed -= connectArgs_Completed;
                    _connectSocket.Shutdown(SocketShutdown.Both);
                }
            }
            catch (Exception E)
            {
                LogHelper.WriteErrorLog(E.Message);
            }
            finally
            {
                try
                {
                    _connectSocket.Close();
                    _receiveEventArgs.AcceptSocket = null;
                    _connectArgs.AcceptSocket = null;
                }
                catch (Exception E)
                {
                    LogHelper.WriteErrorLog(E.Message);
                }
            }
            _listReceiveByte.Clear();
            _connectSocket = null; //释放引用，并清理缓存，包括释放协议对象等资源
            System.Threading.Thread.Sleep(3000);
            Connect(true);
            return true;
        }
    }
}